<template>
    <div class="chat-box-container">
        <template v-if="!error">
            <chat-header @handlePlaySound="handlePlaySound" :siteInfo="siteInfo.site"
                         :playSound="playSound"></chat-header>
            <div class="chat-body flex">
                <div class="left">
                    <div class="content chat-box-content">
                        <div class="box custom-scrollbar" ref="chatBoxContent">
                            <div class="loading-finish" v-if="loadFinish">
                                <span>加载完成</span>
                            </div>
                            <div :class="[serviceUserId==item.fromUserId?'item flex':'item flex self flex-direction-row-reverse']"
                                 v-for="(item,index) in userData.messageList"
                                 :key="index">
                                <div class="avatar">
                                    <el-icon size="14">
                                        <User/>
                                    </el-icon>
                                </div>
                                <div class="chat-content">
                                    <div class="text">{{item.content}}</div>
                                    <div class="time">
                                        {{item.createdAt}}
                                    </div>
                                    <div v-if="serviceUserId!=item.fromUserId" class="message-status">
                                        <span class="is-read" v-if="item.isRead===1">已读</span>
                                        <span class="no-read" v-else>未读</span>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <span :class="[loading?'loading-icon show':'loading-icon']">
                        <el-icon><Loading/></el-icon>
                        </span>
                    </div>
                    <div class="form-container">
                        <textarea v-model="content" class="custom-scrollbar none"/>
                        <el-button class="btn" :loading="!connectStatus" @click="handleSendMessage" type="primary">
                            {{connectStatus?'发送':'正在连接...'}}
                        </el-button>
                    </div>
                </div>
                <div class="right">
                    <company-info :siteInfo="siteInfo.site"></company-info>
                </div>
            </div>
        </template>
        <template v-else>
            <div class="flex align-items-center justify-content-center error-message">{{errorMsg}}</div>
        </template>
        <audio class="audio" :src="audioMp3" ref="newMessage"></audio>
    </div>
</template>

<script setup>
    import ChatHeader from '@/components/ChatHeader.vue';
    import CompanyInfo from '@/components/CompanyInfo.vue';
    import {User, Loading} from '@element-plus/icons-vue';
    import audioMp3 from '@/assets/18.mp3';
    import {ElMessage} from 'element-plus';
    import {onMounted, onBeforeUnmount, getCurrentInstance, reactive, nextTick, ref} from 'vue';
    import Fingerprint from '@fingerprintjs/fingerprintjs';
    import {api} from '@/utils/api';
    import {service} from '@/utils/service';

    const chatBoxContent = ref();
    const {proxy} = getCurrentInstance();
    const connectStatus = ref(false);
    let userData = reactive({
        messageList: []
    });
    let siteInfo = reactive({
        site: {},
        serviceUser: {},
        user: {}
    });
    let serviceUserId = ref('');
    let error = ref(false);
    let errorMsg = ref('错误消息');
    let content = '';
    let loading = ref(false);//是否正在加载
    let scrollTop = ref(10);//当前滚动距离
    let loadFinish = ref(false);//是否加载完成
    let isInit = true;//是否初始化
    let refresh = true;//是否刷新页面
    const newMessage = ref();//消息音
    let playSound = ref(false);//是否播放提示音

    //定义监听事件
    const sockets = {
        //获取消息列表
        async messageList(data) {
            if (data.length < 20) {
                loadFinish.value = true;
            }
            data.reverse();
            userData.messageList = data;
            await scrollBottom();
            chatBoxContent.value.addEventListener('scroll', listenerScroll, true);
        },
        //获取下一段消息列表
        async nextMessageList(data) {
            data.reverse();
            if (data.length < 20) {
                loadFinish.value = true;
            }
            let oldHeight = chatBoxContent.value.scrollHeight;
            userData.messageList.unshift(...data);
            await nextTick(() => {
                chatBoxContent.value.scrollTo({
                    top: chatBoxContent.value.scrollHeight - oldHeight,
                    behavior: 'instant'
                });
                setTimeout(function () {
                    loading.value = false;
                }, 100)
            });
        },
        //成功将消息记录到数据库
        async successAddMessage(data) {
            if (data.code === 1) {
                //添加成功后将消息展示到消息列表
                const messageObj = {
                    ...data.data
                };
                userData.messageList.push(messageObj);
                content = '';
                await scrollBottom();
            } else {
                ElMessage({
                    showClose: false,
                    message: data.msg,
                    type: 'error',
                });
            }
        },
        //接收对方消息
        async acceptMessage(data) {
            connectStatus.value = true;
            userData.messageList.push(data);
            //成功接收后通知对方消息已读
            proxy.$socket.io.emit('notifyAcceptSuccess', {
                toUserId: data['fromUserId'],
                messageId: data['id']
            });//发送消息
            await scrollBottom();
        },
        //消息已读
        messageIsRead() {
            for (let i = 0; i < userData.messageList.length; i++) {
                if (userData.messageList[i].isRead === 0) {
                    userData.messageList[i].isRead = 1;
                }
            }
        },
        async newMessageSound() {
            if (playSound.value && (newMessage.value.paused || newMessage.value.ended)) {
                newMessage.value.play();
            }
        }
    };

    onMounted(async () => {
        isInit = true;
        loadFinish.value = false;
        await connectCustomerService();
        proxy.$addSockets(sockets, proxy);
        proxy.$socket.io.on('connect', async () => {
            connectStatus.value = true;
            if (!refresh) {
                proxy.$socket.io.emit('login', siteInfo.user);
                proxy.$socket.io.emit('isChat');
                ElMessage({
                    showClose: false,
                    message: '网络连接成功',
                    type: 'success',
                });
            }
            refresh = false;
        });
        proxy.$socket.io.on('disconnect', async () => {
            connectStatus.value = false;
            ElMessage({
                showClose: false,
                message: '网络连接失败',
                type: 'error',
            });
        });
        proxy.$socket.io.on('connect_error', async () => {
            connectStatus.value = false;
        });
    });

    onBeforeUnmount(async () => {
        proxy.$socket.io.emit('leaveChat');
        proxy.$removeSockets(sockets, proxy);
        chatBoxContent.value.removeEventListener('scroll', listenerScroll);
    });

    //发送消息
    const handleSendMessage = async () => {
        if (connectStatus.value) {
            if (content.length <= 0) {
                ElMessage({
                    showClose: false,
                    message: '消息不能为空',
                    type: 'warning',
                });
                return;
            }
            proxy.$socket.io.emit('sendMessage', {toUserId: serviceUserId, content});//发送消息
        }
    };

    //聊天内容框滚动到底部
    const scrollBottom = async () => {
        await nextTick(() => {
            chatBoxContent.value.scrollTo({
                top: chatBoxContent.value.scrollHeight,
                behavior: isInit ? 'instant' : 'smooth'
            });
            isInit = false;
        });
    };

    //监听滚动事件
    const listenerScroll = (e) => {
        if (loadFinish.value) {
            return;
        }
        if (e.target.scrollTop < 10 && loading.value === false) {
            if (scrollTop.value > e.target.scrollTop) {
                loading.value = true;
                proxy.$socket.io.emit('getNextMessageList', serviceUserId, userData.messageList.length);//触发获取指定用户id的聊天列表
            }
        }
        scrollTop.value = e.target.scrollTop;
    };

    //连接客服
    const connectCustomerService = () => {
        const params = new URLSearchParams(window.location.search);
        let siteToken = params.get('siteToken');
        if (!siteToken) {
            errorMsg.value = '缺少必要的参数siteToken';
            error.value = true;
            return;
        }
        setTimeout(async () => {
            const visitorId = await generateFingerPrint();
            service.doPost(api['connectService'], {siteToken, visitorId})
                .then(async (response) => {
                    if (response.code === 1) {
                        const data = response.data;
                        serviceUserId = data.serviceUser.id;
                        await connectSocket(data.user);
                        siteInfo.site = data.site;
                        siteInfo.serviceUser = data.serviceUser;
                        siteInfo.user = data.user;
                        error.value = false;
                    } else {
                        error.value = true;
                        errorMsg.value = response.msg + '(尝试刷新页面或联系管理员)';
                    }
                }).catch(() => {
                error.value = true;
                errorMsg.value = '连接客服失败(尝试刷新页面或联系管理员)';
            })
        }, 500);
    };

    //生成浏览器指纹
    const generateFingerPrint = async () => {
        const fpPromise = await Fingerprint.load();
        const result = await fpPromise.get();
        return result.visitorId;
    };

    //连接socket
    const connectSocket = (user) => {
        proxy.$socket.io.open();
        proxy.$socket.io.emit('login', user);
        proxy.$socket.io.emit('getMessageList', serviceUserId);//触发获取聊天列表
    };

    //切换消息提示音
    const handlePlaySound = (isPlay) => {
        playSound.value = isPlay;
    }
</script>

<style lang="less">
    html, body {
        height: 100%;
        margin: 0;
        padding: 0;
        min-height: 500px;
    }

    .custom-scrollbar {

        &.none {
            &::-webkit-scrollbar {
                width: 0;
            }
        }

        &::-webkit-scrollbar-button {
            display: none;
        }

        &::-webkit-scrollbar {
            width: 8px;
            -webkit-border-radius: 10px;
            -moz-border-radius: 10px;
            border-radius: 10px;
        }

        &::-webkit-scrollbar-thumb {
            background: #ddd;
            -webkit-border-radius: 5px;
            -moz-border-radius: 5px;
            border-radius: 5px;
        }
    }

    .flex {
        display: flex;

        &.flex-direction-row-reverse {
            flex-direction: row-reverse;
        }

        &.align-items-center {
            align-items: center;
        }

        &.justify-content-center {
            justify-content: center;
        }

        .flex-grow-1 {
            flex-grow: 1;
        }

    }

    #app {
        font-family: Avenir, Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        height: 100%;
        background-image: url('https://affim.baidu.com/_nuxt/img/index_bg.ecdeed1.png');
        background-position: center top;
        -webkit-background-size: cover;
        background-size: cover;
        padding: 3px 0;
        -webkit-box-sizing: border-box;
        -moz-box-sizing: border-box;
        box-sizing: border-box;
    }

    .chat-box-container {
        box-shadow: 0 8px 40px 0 rgb(0 0 0 / 20%);
        border-radius: 8px;
        overflow: hidden;
        width: 800px;
        margin: 0 auto;
        height: 100%;
        background: #fff;

        audio {
            display: none;
        }

        .error-message {
            text-align: center;
            height: 100%;
            width: 100%;
        }

        .chat-body {
            height: calc(100% - 60px);

            .left {
                width: 550px;
                border-right: 1px solid #ddd;
                height: 100%;

                .content {
                    height: calc(100% - 100px);
                    overflow: hidden;
                    position: relative;

                    .box {
                        height: 100%;
                        background: #F2F6FC;
                        padding: 15px;
                        -webkit-box-sizing: border-box;
                        -moz-box-sizing: border-box;
                        box-sizing: border-box;
                        overflow: auto;

                        .loading-finish {
                            text-align: center;
                            font-size: 12px;
                            position: relative;
                            height: 1px;
                            background: #dcdfe6;
                            margin: 10px 0;

                            span {
                                display: inline-block;
                                background: #F2F6FC;
                                width: 80px;
                                position: absolute;
                                height: 20px;
                                line-height: 20px;
                                top: 50%;
                                margin-top: -10px;
                                left: 50%;
                                margin-left: -40px;
                                color: #999;
                            }
                        }

                        .item {
                            margin: 20px 0;

                            .avatar {
                                width: 36px;
                                height: 36px;
                                line-height: 40px;
                                -webkit-border-radius: 50%;
                                -moz-border-radius: 50%;
                                border-radius: 50%;
                                border: 1px solid #ddd;
                                text-align: center;
                            }

                            .chat-content {
                                position: relative;
                                background: #ddd;
                                font-size: 12px;
                                padding: 10px;
                                -webkit-border-radius: 3px;
                                -moz-border-radius: 3px;
                                border-radius: 3px;
                                border-bottom-right-radius: 20px;
                                margin-left: 10px;
                                max-width: 250px;
                                text-align: left;

                                &:hover {
                                    .time {
                                        opacity: 1;
                                    }
                                }

                                .time {
                                    position: absolute;
                                    left: 0;
                                    min-width: 150px;
                                    top: 105%;
                                    font-size: 12px;
                                    color: #999;
                                    opacity: 0;
                                    -webkit-transition: opacity 0.3s linear 0s;
                                    -moz-transition: opacity 0.3s linear 0s;
                                    -ms-transition: opacity 0.3s linear 0s;
                                    -o-transition: opacity 0.3s linear 0s;
                                    transition: opacity 0.3s linear 0s;
                                }
                            }

                            &.self {
                                .avatar {
                                    background: #ef8d81;
                                    color: #fff;
                                    border: 1px solid #ef8d81;
                                }

                                .chat-content {
                                    -webkit-border-radius: 3px;
                                    -moz-border-radius: 3px;
                                    border-radius: 3px;
                                    border-bottom-left-radius: 20px;
                                    border-bottom-right-radius: 3px;
                                    margin-left: unset;
                                    margin-right: 10px;
                                    background: #5d9afe;
                                    color: #fff;

                                    .time {
                                        left: unset;
                                        right: 0;
                                        text-align: right;
                                    }

                                    .message-status {
                                        position: absolute;
                                        font-size: 12px;
                                        right: 100%;
                                        top: 50%;
                                        color: #000;
                                        width: 40px;
                                        text-align: center;
                                        -webkit-transform: scale(0.9);
                                        -moz-transform: scale(0.9);
                                        -ms-transform: scale(0.9);
                                        -o-transform: scale(0.9);
                                        transform: scale(0.9);
                                    }
                                }
                            }
                        }
                    }

                    .loading-icon {
                        -webkit-animation: loading 2s linear 0s infinite;
                        -o-animation: loading 2s linear 0s infinite;
                        animation: loading 2s linear 0s infinite;
                        width: 16px;
                        height: 16px;
                        display: inline-block;
                        position: absolute;
                        -webkit-transition: top 0.3s linear 0s;
                        -moz-transition: top 0.3s linear 0s;
                        -ms-transition: top 0.3s linear 0s;
                        -o-transition: top 0.3s linear 0s;
                        transition: top 0.3s linear 0s;
                        top: -50px;

                        &.show {
                            top: 10px;
                        }
                    }
                }

                .form-container {
                    height: 100px;
                    position: relative;

                    textarea {
                        border: none;
                        height: 100%;
                        width: 100%;
                        outline: none;
                        resize: none;
                        padding: 10px;
                        -webkit-box-sizing: border-box;
                        -moz-box-sizing: border-box;
                        box-sizing: border-box;
                    }

                    .btn {
                        position: absolute;
                        bottom: 10px;
                        right: 20px;
                    }
                }
            }

            .right {
                width: 250px;
                overflow: auto;
            }
        }
    }
</style>
